/**
*  @class Directory
*
*  @brief
*
*  @author William McVicar
*/

#pragma once

#ifndef __Directory_H_INCLUDED__
#define __Directory_H_INCLUDED__

//  Library Includes

//  Local Includes
#include "Vector.h"

//  Macros

//  Forward Declarations

//  Types

//  Constants

//  Prototypes

namespace Protein
{

class Directory
{
   //Member Functions
public:

	/**
	*	Constructor
	*/
	Directory();

	/**
	*	Copy constructor
	*
	*	@param other The directory to copy into this
	*	@author William McVicar
	*/
	Directory( const Directory& other );

	/**
	*	Assignment operator
	*
	*	@param rhs The directory to assign to this
	*	@author William McVicar
	*/
	Directory& operator=( const Directory& rhs );

	/**
	*	Constructor
	*
	*	@param _krPath The path to store in this directory
	*	@author William McVicar
	*/
	Directory( const std::string& _krPath );

	/**
	*	Constructor
	*
	*	@param _szPath The path to store in this directory
	*	@author William McVicar
	*/
	Directory( const c8* _szPath );

	/**
	*	Destructor
	*/
	~Directory();

	/**
	*	Equality operator
	*
	*	@param other The directory to check for equality with this
	*	@return true if they are equal false if not.
	*	@author William McVicar
	*/
	bool operator==( const Directory& other );

	/**
	*	This function adds a subdirectory to this directory.
	*
	*	@param _krSubDirectory The path to the subdirectory to add
	*	@param _bAppendParent This will append the m_Path to the path of
	*						  the subdirectory being added.
	*	@author William McVicar
	*/
	void AddSubDirectory( const std::string& _krSubDirectory, bool _bAppendParent );

	/**
	*	This function adds a subdirectory to this directory.
	*
	*	@param _szSubDirectory The path to the subdirectory to add
	*	@param _bAppendParent This will append the m_Path to the path of
	*						  the subdirectory being added.
	*	@author William McVicar
	*/
	void AddSubDirectory( const c8* _szSubDirectory, bool _bAppendParent );

	/**
	*	This function adds a subdirectory and all its subdirectoies to 
	*	this directory.
	*
	*	@param _krSubDirectory The path to the subdirectory to add
	*	@param _bIsVirtual Determines if the subdirectory being added is virtual or not.
	*	@author William McVicar
	*/
	void AddSubDirectoriesRecursive( const std::string& _krSubDirectory, bool _bIsVirtual = false );

	/**
	*	This function adds all this directories subdirectoies to 
	*	this directory.
	*
	*	@author William McVicar
	*/
	void AddSubDirectoriesRecursive();

	/**
	*	This function adds a subdirectory and all its subdirectoies to 
	*	this directory.
	*
	*	@param _szSubDirectory The path to the subdirectory to add
	*	@param _bIsVirtual Determines if the subdirectory being added is virtual or not.
	*
	*	@author William McVicar
	*/
	void AddSubDirectoriesRecursive( const c8* _szSubDirectory, bool _bIsVirtual = false );

	/**
	*	This function will remove all subdirectories from this directory.
	*	@author William McVicar
	*/
	void ClearSubdirectories();

	/**
	*	This function gets all the subdirectories of this directory.
	*
	*	@return a container of all the subdirectories
	*	@author William McVicar
	*/
	const std::vector< Directory >& GetSubDirectories() const;

	/**
	*	This function gets all the subdirectories of this directory.
	*
	*	@param _rSubDirectories The container to store all of the 
	*							subdirectories.
	*	@author William McVicar
	*/
	void GetSubDirectories( std::vector< Directory >& _rSubDirectories );

	/**
	*	This function removes the subdirectory at _iIndex
	*
	*	@param _iIndex the index of the subdirectory to remove
	*	@author William McVicar
	*/
	void RemoveSubDirectory( i32 _iIndex );

	/**
	*	This function removes the subdirectory at whos path
	*	is _szSubDirectory
	*
	*	@param _szSubDirectory the path of the subdirectory to remove
	*	@author William McVicar
	*/
	void RemoveSubDirectory( const c8* _szSubDirectory );

	/**
	*	Accessor for the path member of this Directory
	*
	*	@return The path of this Directory
	*	@author William McVicar
	*/
	const std::string& GetPath() const;

	/**
	*	Accessor for the path member of this Directory
	*
	*	@return The path of this Directory as a c-string
	*	@author William McVicar
	*/
	const c8* GetPathCStr() const;

	/**
	*	Mutator for the path variable of this Directory
	*
	*	@warning Doing this will destroy all paths to subdirectories which
	*			 aren't virtual.
	*	@param _krNewPath the new path to set.
	*	@author William McVicar
	*/
	void SetPath( const std::string& _krNewPath );

	/**
	*	Mutator for the path variable of this Directory
	*
	*	@warning Doing this will destroy all paths to subdirectories which
	*			 aren't virtual.
	*	@param _szNewPath the new path to set.
	*	@author William McVicar
	*/
	void SetPath( const c8* _szNewPath );

protected: 

private: 

#if defined( PROTEIN_PLATFORM_WINDOWS )
void AddSubDirectoriesRecursiveWin32( const std::string& _krSubDirectory, bool _bIsVirtual );
void AddSubDirectoriesRecursiveWin32();
#elif defined( PROTEIN_PLATFORM_IOS )
void AddSubDirectoriesRecursiveIOS( const std::string& _krSubDirectory, bool _bIsVirtual );
void AddSubDirectoriesRecursiveIOS();
#endif

   //Member Variables
public:

protected: 

private: 

  std::vector< Directory >	m_Subdirectories;
	std::string					      m_Path;

};

PROTEIN_INLINE void Directory::RemoveSubDirectory( i32 _iIndex )
{
	m_Subdirectories.erase( m_Subdirectories.begin() + _iIndex );
}

PROTEIN_INLINE void Directory::RemoveSubDirectory( const c8* _szSubDirectory )
{
	std::string path = m_Path + _szSubDirectory; 
	Directory subDir( path );
	std::vector< Directory >::iterator iter = std::find( m_Subdirectories.begin(), m_Subdirectories.end(), subDir );
	if( iter != m_Subdirectories.end() )
		m_Subdirectories.erase( iter );
}

PROTEIN_INLINE const std::string& Directory::GetPath() const
{
	return m_Path;
}

PROTEIN_INLINE const c8* Directory::GetPathCStr() const
{
	return m_Path.c_str();
}

PROTEIN_INLINE void Directory::SetPath( const std::string& _krNewPath )
{
	m_Path = _krNewPath;
}

PROTEIN_INLINE void Directory::SetPath( const c8* _szNewPath )
{
	m_Path = _szNewPath;
}

PROTEIN_INLINE const std::vector< Directory >& Directory::GetSubDirectories() const
{
	return m_Subdirectories;
}

PROTEIN_INLINE void Directory::GetSubDirectories( std::vector< Directory >& _rSubDirectories )
{
	memcpy( &m_Subdirectories[0], &_rSubDirectories[0], sizeof( Directory ) * m_Subdirectories.size() );
}


}

#endif //__Directory_H_INCLUDED__
